Imports System.IO
Imports cmplib01
Imports FMPLib01


Public Class CampaignerCombatEngineB

    Implements ICombatEngine.ICombatEngine

    Private Const c_Module As String = "CampaignerCombatEngine"
    Private Const c_MaxChitDetectionLevel As Integer = 12
    Private Const c_RoadDistance As Integer = 5

    Private Structure Boiler
        Public Chit As ChitMember
        Public Location As Point
        Public TerrainMod As Single
        Public Size As Single
        Public LosPower As Single
        Public LosRange As Long
        Public Detected As Boolean
        Public OwningFactionKey As String
        Public OwningPlayerID As Integer
        Public ZOCRange As Integer
    End Structure

    Private Enum OnRoadType
        NoRoad = 0
        UnimprovedRoad = 1
        ImprovedRoad = 2
        MajorRoad = 3
    End Enum


    Public Event PercentComplete(ByVal percent As Integer)

    Private m_UsesContactCombat As Boolean = True
    Private m_UsesRangedCombat As Boolean = False
    Private m_UsesPreCombatWindow As Boolean = True
    Private _currentPhase As Integer = 0
    Private _executedPhases As Integer

    Private contactRange As Int16 = 32 ' this is for determining if two units are touching
    Private joinCombatDistance As Int16 = 32   ' this is for determining if a new combat should be made, or if to add the targets in question to 
    '                                                              an existing combat.

    Private ptrGameData As cmplib01.CampaignerGameData
    Private ptrFMPData As FMPLib01.FlexMapData

    Private arrDistance(10, 10) As Single ' used for distance between chits
    Private arrFactionA(1) As Boiler
    Private arrFactionB(1) As Boiler

    Private detectionHalt As Boolean = False    '// once a unit is NEWLY detected, we HALT the turn there. 

    Public ReadOnly Property ExecutedPhases() As Integer
        Get
            Return _executedPhases
        End Get

    End Property


    Public Function CombatReportString() As String Implements ICombatEngine.ICombatEngine.CombatReportString
        ' this returns a combat report in string format

    End Function

    Public Function CombatReportXML() As System.Xml.XmlDataDocument Implements ICombatEngine.ICombatEngine.CombatReportXML
        ' this returns as combat report in xml format

    End Function

    Public Function Combats() As cmplib01.Battles Implements ICombatEngine.ICombatEngine.Combats
        ' returns a collection of combats and whether they are finished or not.

    End Function

    Public Sub GenerateCombatTurn(ByRef gameData As cmplib01.CampaignerGameData, ByVal fmpData As FMPLib01.FlexMapData, ByVal PhaseCount As Short) Implements ICombatEngine.ICombatEngine.GenerateCombatTurn
        Try
            ptrGameData = gameData
            ptrFMPData = fmpData

            'TODO: Turn 0 is DEPLOYMENT TURN. No movement, detection only.

            'Dim i As Int16
            'Dim key As String
            'Dim gc As cmplib01.GroundChitType
            Dim skipBit As Byte = 0
            Dim skipBitStop As Integer = 0 'PhaseCount / 10
            Dim FactA As cmplib01.Faction
            Dim fukov As String
            Dim a As Int16 ' faction a in arrfactiona boiler
            Dim b As Int16
            Dim removeCollection As New Collection

            For Each fukov In ptrGameData.Faction_g.HT.Keys
                FactA = ptrGameData.Faction_g.Item(fukov)
                ' The first faction is faction a
                Exit For
            Next

            RemoveTheDead()
            ResetStatus()
            ResetBoiler()
            PopulateBoiler()


            ' MOVEMENT
            For _currentPhase = 0 To PhaseCount
                'Dim unit As cmplib01.UnitType
                'TODO: Tokens. Eventually. Maybe. Who knows.
                Try
                    RaiseEvent PercentComplete((_currentPhase / PhaseCount) * 100)
                Catch
                End Try

                ' reset boiler faction counters
                a = 0
                b = 0

                For Each mem As ChitMember In ptrGameData.Chits
                    Select Case mem.UnitType

                        Case GroundChitClass_cgd.Battlegroup
                            Dim batt As BattlegroupChit = mem

                            MoveUnit2(batt, PhaseCount)
                            If batt.OwningFaction.FactionID = FactA.FactionID Then
                                arrFactionA(a).Location = batt.Location
                            Else
                                arrFactionB(b).Location = batt.Location
                            End If

                            '// historical
                            batt.historicalPosition.Add(batt.Location)

                            '// contact check
                            ContactCheck(batt, _currentPhase)

                            ZOCBehavior(batt)
                    End Select
                Next mem

                ' DETECTION - this is the actual detection check.
                PointToPointBoiler()

                ' AREA OBJECTIVES
                AreaObjectiveOwnership()
                AssignAOownership()

                ' HALT ON NEW DETECTION
                If detectionHalt = True Then
                    detectionHalt = False
                    Exit For
                End If

            Next ' Phase Count

            _executedPhases = _currentPhase

            ' HIDE UNVIEWED
            DecreaseDetectionForUnspotted()

            ' TITANIC CHITS
            ' titanic objects now get a +1 detection. This means that an 'unspotted' one will always have a question mark until a unit is close enough to see it.
            IncreaseDetectionForTitanicObjects()

            ResetDeploymentValues()
        Catch ex As Exception
            HandleException("CampaignerCombatEngine.GenerateTurn", ex)
        End Try
    End Sub

    Private Sub IncreaseDetectionForTitanicObjects()
        'Dim gcKey As String
        'Dim gc As cmplib01.GroundChitType
        Dim FactA As cmplib01.Faction
        Dim factB As cmplib01.Faction
        Dim fukov As String

        For Each fukov In ptrGameData.Faction_g.HT.Keys
            If Not FactA Is Nothing Then
                factB = ptrGameData.Faction_g.Item(fukov)   ' if A is assigned already then we know that this is the other one. This only works with 2 factions of course.
            End If
            If FactA Is Nothing Then FactA = ptrGameData.Faction_g.Item(fukov)
        Next

        For Each mem As ChitMember In ptrGameData.Chits
            If mem.OwningFaction.Equals(FactA) Then
                If mem.Size >= 10000 Then
                    IncreaseDetectionOnTarget(factB, mem, False)
                End If
            Else
                If mem.Size > 10000 Then
                    IncreaseDetectionOnTarget(FactA, mem, False)
                End If
            End If
        Next

    End Sub

    Private Sub RemoveTheDead()

    End Sub

    Private Sub AreaObjectiveOwnership()

        Dim ao As AreaObjective
        'Dim unit As GroundChitType
        'Dim unitKey As String

        '// Faction A is the first faction, Faction B is the second
        '// reset the area objective information first.
        ResetAOInfo()

        Try
            For Each mem As ChitMember In ptrGameData.Chits
                If Not mem.Status = GroundUnitStatus_cgd.Dead OrElse Not mem.Status = GroundUnitStatus_cgd.NotDeployed Then
                    For Each ao In ptrGameData.AreaObjectives
                        If ao.ObjectiveRegion.IsVisible(mem.Location) Then
                            If Not ao.FactionsPresent.Contains(mem.OwningFaction) Then
                                ao.FactionsPresent.Add(mem.OwningFaction)
                            End If
                        End If
                    Next
                End If
            Next

        Catch ex As Exception
            HandleException(c_Module, ex)
        End Try

    End Sub

    Private Sub ResetAOInfo()
        Dim ao As AreaObjective
        For Each ao In ptrGameData.AreaObjectives
            ao.FactionsPresent = New ArrayList
        Next
    End Sub

    Private Sub AssignAOownership()
        Dim ao As AreaObjective
        For Each ao In ptrGameData.AreaObjectives
            Select Case ao.FactionsPresent.Count
                Case Is = 0
                Case Is = 1
                    ao.OwningFaction = ao.FactionsPresent.Item(0).factionid
                    ao.IsContested = False
                Case Else
                    ao.IsContested = True
            End Select
        Next
    End Sub

    Private Sub ZOCBehavior(ByRef unit As BattlegroupChit)
        Dim closestDistance As Integer = 500000
        Dim distance As Integer
        Dim validEnemy As Boiler
        Dim factA As Faction
        Dim factAkey As String
        Dim enemyBoil() As Boiler
        Dim bInZOC As Boolean
        'Dim newWap As New Point


        '// find out which boiler array we need to use
        '// factionA array is the first found faction in the collection

        For Each factAkey In ptrGameData.Faction_g.HT.Keys
            factA = ptrGameData.Faction_g.Item(cmplib01.CampaignerGameData.CDGKEY_FACTION & unit.OwningFaction.FactionID)
            Exit For
        Next

        If factAkey = ptrGameData.CDGKEY_FACTION & unit.OwningFaction.FactionID Then
            enemyBoil = arrFactionB
        Else
            enemyBoil = arrFactionA
        End If

        Dim this As Boiler
        For Each this In enemyBoil
            distance = XYDistance(unit.Location, this.Location)
            If (distance < closestDistance) AndAlso (distance <= this.ZOCRange) Then
                validEnemy = this
                closestDistance = distance
                bInZOC = True
            End If
        Next

        '// now behave!
        If Not bInZOC Then Exit Sub
        Dim thisFact As Faction

        If unit.OwningFaction.FactionID = factA.FactionID Then
            thisFact = factA
        Else
            thisFact = ptrGameData.Faction_g.Item(cmplib01.CampaignerGameData.CDGKEY_FACTION & unit.OwningFaction.FactionID)
        End If

        Dim target As ChitMember = validEnemy.Chit 'ptrGameData.AllChits(validEnemy.ChitKey)
        IncreaseDetectionOnTarget(thisFact, target)

        Select Case unit.order
            Case Is = "Engage"
                unit.waypoints.Clear()
                Dim newwap As New SmartWaypoint
                newwap.LOC = validEnemy.Chit.Location
                unit.waypoints.add(newWap)
            Case Is = "Withdraw"
                unit.waypoints.Clear()
                Dim newwap As New SmartWaypoint
                newwap.LOC = validEnemy.Location

                Dim xStr As Single
                Dim yStr As Single
                GetXYStrength(unit.Location, validEnemy.Location, xStr, yStr)
                If validEnemy.ZOCRange > closestDistance Then
                    '                   newwap.X -= xStr * (closestDistance * 2)
                    '                    newwap.Y -= yStr * (closestDistance * 2)

                    newwap.LOC = New Point(validEnemy.Chit.Location.X - (xStr * (closestDistance * 2)), validEnemy.Chit.Location.Y - (yStr * (closestDistance * 2)))

                End If

                unit.waypoints.add(newWap)
            Case Else
                '// clear all waypoints
                unit.waypoints.Clear()
        End Select

    End Sub

    Private Function MoveUnit2(ByRef unit As BattlegroupChit, ByVal PhaseCount As Short) As Boolean
        Dim moveCost As Single
        Dim moveModifier As Single
        Dim speed As Single
        Dim newLocation As New Point
        Dim wap As SmartWaypoint
        Dim roadBonus As Single
        Dim sm As New SMVector
        Dim dailyRate As Single = 1

        Try
            Select Case unit.Status
                'Case GroundUnitStatus_cgd.LoadingTransport, GroundUnitStatus_cgd.InTransport
                '    unit.Status = GroundUnitStatus_cgd.InTransport
                '    '// update the transported unit's location
                '    unit.Location = unit.TransportingIn.Location
                '    '// clear old waypoints for this sukka
                '    unit.Waypoints.Clear()
                '    Return True
                Case GroundUnitStatus_cgd.Moving
                Case GroundUnitStatus_cgd.OK
                    'Case GroundUnitStatus_cgd.UnloadingFromTransport
                Case Else
                    Return False '// we're not ok to move.
            End Select

            If unit.Waypoints.Count = 0 Then
                unit.Status = GroundUnitStatus_cgd.OK
                unit.MoveRemaining = 0
                Return False
            End If

            If unit.MoveRemaining <= 0 Then
                unit.Status = GroundUnitStatus_cgd.OK
                unit.MoveRemaining = 0
                Return False
            End If

            '// Road bonus
            Select Case PointIsOnRoad(unit.Location)
                Case OnRoadType.NoRoad : roadBonus = 1
                Case OnRoadType.UnimprovedRoad : roadBonus = 2
                Case OnRoadType.ImprovedRoad : roadBonus = 3
                Case OnRoadType.MajorRoad : roadBonus = 4
            End Select

            speed = unit.EffectiveSpeed / PhaseCount

            speed *= roadBonus
            moveModifier = ptrFMPData.MovementCost(unit.Location, unit.MovementClassID) * 0.01
            moveCost = moveModifier

            speed *= moveCost

            '// now, check for daily turn rate.
            If ptrGameData.TurnLength = TurnLength_cgd.FullDay Then
                dailyRate = 0.25
            End If

            speed *= dailyRate

            ' ''If speed < 3 Then speed = 3
            If speed >= 3 Then
                unit.MoveAccumulated = speed
            Else
                unit.MoveAccumulated += speed
            End If

            If unit.MoveAccumulated >= 3 Then
                speed = unit.MoveAccumulated
                unit.MoveAccumulated = 0
            Else
                speed = 0
            End If

            '// get next coordinate (not using THIS crapola though-ola
            wap = unit.Waypoints(0)

            Dim newLocationF As PointF = sm.GeneratePtOnVector(New PointF(unit.Location.X, unit.Location.Y), New PointF(wap.LOC.X, wap.LOC.Y), speed)

            newLocation.X = newLocationF.X
            newLocation.Y = newLocationF.Y

            '// check distance to end of waypoint
            If XYDistance(unit.Location, wap.LOC) <= XYDistance(unit.Location, newLocation) Then
                '// the waypoint is closer
                newLocation.X = wap.LOC.X
                newLocation.Y = wap.LOC.Y
                unit.waypoints.RemoveAt(0)
                '// get the next order, if there is one.
                If unit.waypoints.Count > 0 Then unit.order = unit.waypoints.item(0).OrderText
            End If

            '// check to make sure we are moving into terrain that the movement class can
            If ptrFMPData.MovementAllowed(newLocation, unit.MovementClassID) = False Then
                '// check for bridges? bridges allow a unit to move over 'Impassable' terrain. If you were to put a bridge
                '// across the top of a stinking mountain, then you would be able to cross the mountain. I suppose the 
                '// word TUNNEL should be used instead!
                '// Flexmap should do this for us. Shouldn't it?
                unit.InvalidWaypoint = True
                Return False
            End If

            '// hmmn... roads?
            If speed > 0 Then unit.DistanceTravelled += (speed + speed * moveCost) / roadBonus

            ' ''If unit.DistanceTravelled > (unit.EffectiveSpeed * dailyRate) Then
            ' ''    Return False
            ' ''End If

            unit.Location = newLocation

        Catch ex As Exception
            HandleException("CampaignerCombatEngine.MoveUnit2", ex)
        End Try

    End Function

    Private Function PointIsOnRoad(ByRef hitPt As Point) As OnRoadType
        '// returns true if the hit point is within tolerance range of any road.
        Dim pt1 As Point
        Dim vx As Single
        Dim vy As Single
        Dim bOutOfRange As Boolean

        '\\equation of the line
        'm = dy/dx
        'y = mx + b
        'a = x intercept
        'b = y intercept
        'ax + by + c = 0

        Dim roadie As Road

        For Each roadie In ptrFMPData.Roads
            pt1.X = roadie.X1
            pt1.Y = roadie.Y1
            vx = roadie.X2 - roadie.X1
            vy = roadie.Y2 - roadie.Y1
            ' check to see if the vectors point in the same or different directions
            If (DistPointToLine(hitPt.X, hitPt.Y, 0, pt1.X, pt1.Y, 0, vx, vy, 0, bOutOfRange)) < c_RoadDistance Then
                If Not bOutOfRange Then
                    Select Case roadie.RoadType
                        Case FlexMapData.RoadType.ImprovedRoad : Return OnRoadType.ImprovedRoad
                        Case FlexMapData.RoadType.MajorRoad : Return OnRoadType.MajorRoad
                    End Select
                End If
            End If
        Next

        Return OnRoadType.NoRoad

    End Function


    '// detection
    Private Sub PointToPointBoilerOld()
        '// this is the Point to Point detection boiler. A little different than the Orbital one. yeah.

        '// this sub now does two detection attempts. One is 'terrain detection' where intervening terrain is
        '// ignored, but the highest detection attainable is 2 (results in a question mark). 
        '// the second method is a direct line of sight, where terrain between the units 'consumes' los range
        '// This will increase the detection on the target to 'known', although, it could simply increase
        '// each turn as it used to... hmmn.

        Dim a As Integer
        Dim b As Integer
        Dim DetectingFaction As Faction
        Dim DetectingChit As ChitMember
        Dim TargetChit As ChitMember
        Dim dist As Integer

        Try

            ' DO LOS for faction A against the evil faction B
            For a = 0 To arrFactionA.GetUpperBound(0)
                For b = 0 To arrFactionB.GetUpperBound(0)
                    If Not arrFactionB(b).Detected Then
                        DetectingChit = arrFactionA(a).Chit
                        TargetChit = arrFactionB(b).Chit

                        dist = XYDistance(DetectingChit.Location, TargetChit.Location)

                        If dist <= arrFactionA(a).LosRange Then
                            DetectingFaction = ptrGameData.Faction_g.Item(arrFactionA(a).OwningFactionKey)

                            '// do our "detection" check
                            If DetectionCheck(DetectingChit, TargetChit) = True Then
                                '// it is DETECTED and so, should be a "?".
                                HandleDetection(DetectingFaction, TargetChit, False)
                            End If

                            '// do our point to point detection
                            PointToPointDetection(DetectingChit, TargetChit, DetectingFaction)
                        End If
                    End If
                Next
            Next
            ' DO LOS for faction B against the heretics in faction A
            For b = 0 To arrFactionB.GetUpperBound(0)
                For a = 0 To arrFactionA.GetUpperBound(0)
                    If Not arrFactionA(a).Detected Then

                        DetectingChit = arrFactionB(b).Chit
                        TargetChit = arrFactionA(a).Chit
                        dist = XYDistance(DetectingChit.Location, TargetChit.Location)

                        If dist <= arrFactionB(b).LosRange Then

                            DetectingFaction = ptrGameData.Faction_g.Item(arrFactionB(b).OwningFactionKey)
                            If DetectionCheck(DetectingChit, TargetChit) = True Then
                                HandleDetection(DetectingFaction, TargetChit, False)
                            End If
                            PointToPointDetection(DetectingChit, TargetChit, DetectingFaction)
                        End If
                    End If
                Next

            Next

        Catch ex As Exception
            HandleException("CampaignerCombatEngine.PointToPointBoiler", ex)
        End Try

    End Sub

    Private Sub PointToPointBoiler()
        Dim a As Integer
        Dim b As Integer
        Dim DetectingFaction As Faction
        Dim DetectingChit As ChitMember
        Dim TargetChit As ChitMember
        Dim dist As Integer

        '// wow. all in one loop instead of two. Schweet. That should take 1/2 the amount of time!
        Try
            For a = 0 To arrFactionA.GetUpperBound(0)
                For b = 0 To arrFactionB.GetUpperBound(0)
                    '// the distance between the two is the same of course
                    dist = XYDistance(arrFactionA(a).Chit.Location, arrFactionB(b).Chit.Location)
                    '// do a vs b
                    If Not arrFactionB(b).Detected Then
                        DetectingChit = arrFactionA(a).Chit
                        TargetChit = arrFactionB(b).Chit
                        BaseDetection(arrFactionA(a), DetectingChit, TargetChit, dist)
                    End If

                    '// do b vs a
                    If Not arrFactionA(a).Detected Then
                        DetectingChit = arrFactionB(b).Chit
                        TargetChit = arrFactionA(a).Chit
                        BaseDetection(arrFactionB(b), DetectingChit, TargetChit, dist)
                    End If
                Next
            Next
        Catch ex As Exception
            HandleException(c_Module, ex)
        End Try
    End Sub

    Private Sub BaseDetection(ByRef detectingBoiler As Boiler, ByRef detectingChit As ChitMember, ByRef targetChit As ChitMember, ByVal dist As Long)
        Try
            If dist <= detectingBoiler.LosRange Then
                '// check simple detection
                If DetectionCheck(detectingChit, targetChit) = True Then
                    '// this means detected? huh?
                    HandleDetection(detectingChit.OwningFaction, targetChit, False)
                End If
                '// check p2p detection
                PointToPointDetection(detectingChit, targetChit, detectingChit.OwningFaction)
            End If
        Catch ex As Exception
            HandleException(c_Module, ex)
        End Try
    End Sub

    Private Sub PointToPointDetection(ByRef DetectingChit As ChitMember, ByRef TargetChit As ChitMember, ByRef DetectingFaction As Faction)
        '// this is the point to point, meaning that the distance directly from one chit to the target chit is calculated
        '// it will short-circuit if the detecting chit "runs out" of range. Execution should only get here IF detection is
        '// a possibility. If the units are too far away to even detect each other, we shouldn't get here.
        '// we never count the point from origin.

        Dim MoveStep As Integer = 5
        Dim TotalCost As Single
        Dim done As Boolean
        Dim LOSCost As Single
        Dim i As Integer
        Dim samplepoint As PointF
        Dim sm As New SMVector
        Dim diff As Single

        Dim losRangeInPixels As Integer = DetectingChit.LOS * (ptrFMPData.PixelsPerOneMile)

        '// we'll adjust for size baby!
        'MIXEDMODE is the new detection mode. We don't adjust for size or power in that mode.
        '           if the target is in the zone shown, he is spotted. Period.
        '           if mixedmode is off (0) then we calculate using power and target size.
        '#If MIXEDMODE = 0 Then
        '    losRangeInPixels *= (TargetChit.Size / 100)
        '#End If

        Dim rangeToTarget As Integer = XYDistance(DetectingChit.Location, TargetChit.Location)
        Dim currentSampleDistance As Integer

        Try

            Do Until done
                i += MoveStep
                samplepoint = sm.GeneratePtOnVector(New PointF(DetectingChit.Location.X, DetectingChit.Location.Y), New PointF(TargetChit.Location.X, TargetChit.Location.Y), i)

                LOSCost = ptrFMPData.LOSCost(New Point(samplepoint.X, samplepoint.Y))

                '#If MIXEDMODE = 0 Then
                '    '// adjust for LOS Power!! POWER POWER POWER!!
                '    If LOSCost > 1 Then
                '        diff = LOSCost - 1
                '        diff *= (DetectingChit.LOSPower / 100)
                '        LOSCost = diff + 1
                '        If LOSCost < 1 Then LOSCost = 1
                '    End If
                '#End If

                TotalCost += MoveStep * LOSCost

                currentSampleDistance = XYDistance(New Point(samplepoint.X, samplepoint.Y), DetectingChit.Location)
                If currentSampleDistance >= rangeToTarget Then
                    '// detected
                    '#If MIXEDMODE = 0 Then
                    'IncreaseDetectionOnTarget(DetectingFaction, TargetChit)
                    '#Else

                    '// if we're in mixedmode, the unit is completely detected.
                    'IncreaseDetectionOnTarget(DetectingFaction, TargetChit, True)
                    HandleDetection(DetectingFaction, TargetChit, True)
                    '#End If
                    done = True
                End If

                If TotalCost >= losRangeInPixels / 2 Then
                    '// not so detected
                    done = True
                End If
            Loop

        Catch ex As Exception
            HandleException("Campaigner Combat Engine.PointToPointDetection", ex)
        End Try

    End Sub

    Private Sub LOSBoiler()
        ' this sub crunches the data 
        Dim a As Integer
        Dim b As Integer
        Dim SomeFact As cmplib01.Faction
        Dim SomeChit As ChitMember

        For a = 0 To arrFactionA.GetUpperBound(0)
            For b = 0 To arrFactionB.GetUpperBound(0)
                ' check against faction b, if not already detected this turn
                If arrFactionB(b).Detected = False Then
                    If LOSCheck(arrFactionA(a), arrFactionB(b)) = True Then
                        arrFactionB(b).Detected = True
                        ' find this newly targeted chit
                        SomeChit = arrFactionB(b).Chit
                        SomeFact = arrFactionA(a).Chit.OwningFaction
                        IncreaseDetectionOnTarget(SomeFact, SomeChit)
                    End If
                End If
                ' check against faction a, if not already detected this turn
                If arrFactionA(a).Detected = False Then
                    If LOSCheck(arrFactionB(b), arrFactionA(a)) = True Then
                        arrFactionA(a).Detected = True
                        ' find this newly targeted chit
                        SomeChit = arrFactionA(a).Chit
                        SomeFact = ptrGameData.Faction_g.Item(arrFactionB(b).OwningFactionKey)
                        IncreaseDetectionOnTarget(SomeFact, SomeChit)
                    End If
                End If
            Next b
        Next a

    End Sub

    Private Function LOSCheck(ByVal detecter As Boiler, ByVal target As Boiler) As Boolean
        ' basic LOS rules calculate LOS range, LOS power, Target Size, Target Terrain LOS cost, detecter terrain LOS cost
        Dim modifiedDistance As Int32
        Dim trueDistance As Int32        ' this is to determine if a unit or objective is outside the possible detection range.
        Dim DetectingTerrainCost As Single
        Dim TargetTerrainCost As Single
        Dim TargetSize As Single

        ' The actual distance in pixels between the chits
        trueDistance = XYDistance(detecter.Location.X, target.Location.X, detecter.Location.Y, target.Location.Y)

        'If trueDistance < detecter.LosRange Then
        ' modified distance is where we begin trashing the distance!
        modifiedDistance = trueDistance   'well, it has to start somewhere

        ' add each of the distance costs, using the TRUEdistance as starting point
        TargetTerrainCost = modifiedDistance - (modifiedDistance * target.TerrainMod)
        DetectingTerrainCost = modifiedDistance - (modifiedDistance * detecter.TerrainMod)
        modifiedDistance += TargetTerrainCost + DetectingTerrainCost

        ' Modify by Target Size. We're using the MODIFIED distance (coefficient model)
        TargetSize = target.Size
        modifiedDistance += (modifiedDistance - (modifiedDistance * TargetSize))

        ' Modify by Detecting Power, again, using coefficient model 
        modifiedDistance -= ((modifiedDistance * detecter.LosPower) - modifiedDistance)

        If modifiedDistance < detecter.LosRange Then
            Return True
        Else
            Return False
        End If
        'End If

    End Function

    Private Function DetectionCheck(ByRef detecter As ChitMember, ByRef target As ChitMember) As Boolean
        '// it uses the distance, LOS POWER, LOS Cost of both target and detecter and size. Yum.
        Try
            Dim TrueDistance As Int32
            Dim modifiedDistance As Int32
            Dim detectingTerrainCost As Single
            Dim targetTerrainCost As Single
            Dim detectPower As Single
            Dim targetSize As Single
            Dim modifiedLOS As Single

            '// parameters to take into consideration:

            '___PARAMETER________________________________________EFFECT___________________________
            ' terrain cost at both target and detecter          increases modified range
            ' size of target                                    increases detection range
            ' power of detecter                                 modifies detection range

            ' The actual distance in pixels between the chits
            TrueDistance = XYDistance(detecter.Location.X, target.Location.X, detecter.Location.Y, target.Location.Y)

            ' modified distance is where we begin trashing the distance!
            modifiedDistance = TrueDistance   'well, it has to start somewhere

            '// PARAMETER 1: Terrain Costs
            modifiedDistance *= (ptrFMPData.LOSCost(target.Location) + ptrFMPData.LOSCost(detecter.Location))

            '// we use the detecter power to increase apparent detection range
            modifiedLOS = (detecter.LOS * ptrFMPData.PixelsPerOneMile())
            modifiedLOS *= (detecter.LOSPower / 100)
            modifiedLOS *= (target.Size / 100)

            If modifiedDistance < modifiedLOS Then
                Return True
            Else
                Return False
            End If

        Catch ex As Exception
            HandleException("CampaignerCombatEngine.DetectionCheck", ex)
        End Try

    End Function

    Private Sub ResetBoiler()
        ' populate the distance array size
        Dim factAChitCount As Integer
        Dim factBChitCount As Integer
        Dim FactA As cmplib01.Faction
        Dim fukov As String

        For Each fukov In ptrGameData.Faction_g.HT.Keys
            FactA = ptrGameData.Faction_g.Item(fukov)
            Exit For
        Next

        For Each mem As ChitMember In ptrGameData.Chits
            If mem.OwningFaction.Equals(FactA) Then
                factAChitCount += 1
            Else
                factBChitCount += 1
            End If
        Next

        'For Each gcKey In ptrGameData.AllChits.Keys
        '    gc = ptrGameData.AllChits.Item(gcKey)
        '    If gc.OwningFaction = FactA.FactionID Then
        '        '' deal with titanic objects
        '        'If gc.Size >= 10000 Then
        '        '    IncreaseDetectionOnTarget(ptrGameData.Faction_g.Item(cmplib01.CampaignerGameData.CDGKEY_FACTION & gc.OwningFaction), gc, False)
        '        'End If
        '        factAChitCount += 1
        '    Else
        '        '' deal with titanic objects here too
        '        'If gc.Size >= 10000 Then
        '        '    IncreaseDetectionOnTarget(FactA, gc, False)
        '        'End If
        '        factBChitCount += 1
        '    End If
        'Next

        ReDim arrFactionA(factAChitCount - 1)
        ReDim arrFactionB(factBChitCount - 1)

    End Sub

    Private Sub PopulateBoiler()
        Dim a As Integer
        Dim b As Integer
        'Dim gcKey As String
        'Dim gc As cmplib01.GroundChitType
        Dim FactA As cmplib01.Faction
        Dim fukov As String

        For Each fukov In ptrGameData.Faction_g.HT.Keys
            FactA = ptrGameData.Faction_g.Item(fukov)
            Exit For
        Next

        For Each mem As ChitMember In ptrGameData.Chits

            If mem.OwningFaction.Equals(FactA) Then
                arrFactionA(a).Chit = mem
                arrFactionA(a).Location = mem.Location
                arrFactionA(a).TerrainMod = 1    ' ok. so like... none yet.
                arrFactionA(a).Size = (mem.Size * 0.01)
                arrFactionA(a).LosPower = mem.LOSPower * 0.01
                arrFactionA(a).LosRange = (mem.LOS / 2) * ptrFMPData.PixelsPerOneMile
                arrFactionA(a).Detected = 0 ' not detected really. Nope. Well... not yet.
                arrFactionA(a).OwningFactionKey = ptrGameData.CDGKEY_FACTION & mem.OwningFaction.FactionID
                arrFactionA(a).ZOCRange = (mem.ZOC * ptrFMPData.PixelsPerOneMile) / 2
                a += 1
            Else
                arrFactionB(b).Chit = mem
                arrFactionB(b).Location = mem.Location
                arrFactionB(b).TerrainMod = 1    ' ok. so like... none yet.
                arrFactionB(b).Size = (mem.Size * 0.01)
                arrFactionB(b).LosPower = mem.LOSPower * 0.01
                arrFactionB(b).LosRange = (mem.LOS / 2) * ptrFMPData.PixelsPerOneMile
                arrFactionB(b).Detected = 0 ' not detected really. Nope. Well... not yet.                
                arrFactionB(b).OwningFactionKey = ptrGameData.CDGKEY_FACTION & mem.OwningFaction.FactionID
                arrFactionB(b).ZOCRange = (mem.ZOC * ptrFMPData.PixelsPerOneMile) / 2
                b += 1
            End If
        Next

    End Sub


    Private Sub ContactCheck(ByRef unit As ChitMember, ByVal inPhase As Integer)
        ' A unit may be in multiple battles?
        'Dim key As String
        'Dim gc As cmplib01.GroundChitType
        'Dim enemyObj As cmplib01.ObjectiveType
        'Dim enemyUnit As cmplib01.UnitType
        'Dim enemyTok As cmplib01.TokenType

        Try

            For Each target As ChitMember In ptrGameData.Chits
                If target.Status <> GroundUnitStatus_cgd.Dead And target.Status <> GroundUnitStatus_cgd.NotDeployed Then
                    If Not target.OwningFaction.Equals(unit.OwningFaction) Then
                        If XYDistance(target.Location, unit.Location) <= contactRange Then
                            '// in combat range
                            Createbattle(unit, target, inPhase)
                            SetCombatFlag(unit, target)

                            Dim eFaction As cmplib01.Faction = ptrGameData.Faction_g.Item(cmplib01.CampaignerGameData.CDGKEY_FACTION & target.OwningFaction.FactionID)
                            Dim fFaction As cmplib01.Faction = ptrGameData.Faction_g.Item(cmplib01.CampaignerGameData.CDGKEY_FACTION & unit.OwningFaction.FactionID)
                            IncreaseDetectionOnTarget(eFaction, unit, True)
                            IncreaseDetectionOnTarget(fFaction, target, True)
                        End If

                    End If
                End If
            Next


            'For Each key In ptrGameData.AllChits.Keys
            '    gc = ptrGameData.AllChits.Item(key)
            '    If gc.Status <> GroundUnitStatus_cgd.Dead Then
            '        If gc.OwningFaction <> unit.OwningFaction Then
            '            If XYDistance(unit.Location.X, gc.Location.X, unit.Location.Y, gc.Location.Y) <= contactRange Then
            '                ' the chits ARE in combat range
            '                If gc.GroundChitClass = cmplib01.GroundChitClass_cgd.Objective Then
            '                    ' handle player ownership, ok, this doesn't happen here, but its still pretty cool.
            '                    enemyObj = gc
            '                    ' objective attacks are handled a little differently since they can have rules such as garrison
            '                    Createbattle(unit, enemyObj, inPhase)
            '                    ' set the isincombat flag for all players in the objective's owning faction
            '                    SetCombatFlag(unit, enemyObj)
            '                ElseIf gc.GroundChitClass = cmplib01.GroundChitClass_cgd.Unit Then
            '                    If Not unit.Status = cmplib01.GroundUnitStatus_cgd.Engaged Then
            '                        enemyUnit = gc
            '                        ' createbattle is pretty smart and knows what to do according to some rules that came from my BIG head.
            '                        Createbattle(unit, enemyUnit, inPhase)
            '                        ' set the owning players isincombat flag
            '                        SetCombatFlag(unit, enemyUnit)

            '                    End If
            '                End If
            '                Dim eFaction As cmplib01.Faction = ptrGameData.Faction_g.Item(cmplib01.CampaignerGameData.CDGKEY_FACTION & gc.OwningFaction)
            '                Dim fFaction As cmplib01.Faction = ptrGameData.Faction_g.Item(cmplib01.CampaignerGameData.CDGKEY_FACTION & unit.OwningFaction)
            '                IncreaseDetectionOnTarget(eFaction, unit, True)
            '                IncreaseDetectionOnTarget(fFaction, gc, True)
            '            End If
            '        End If
            '    End If
            '   Next
        Catch ex As Exception
            HandleException("CampaignerCombatEngine.ContactCheck", ex)
        End Try

    End Sub

    Private Sub Createbattle(ByRef unit As ChitMember, ByRef target As ChitMember, ByVal inPhase As Integer)
        ' creates a battle, or checks to see if the besieged unit is already in combat, or if there is a combat in this
        ' location already? Hmnn. We don't want to add duplicates. Combat is in the location of the initial contact.
        ' This is the battle LOCATION. Attacking and Defending chit have absolutely no meaning, really.
        ' using the rules found in CampaignerCombat.txt, determine if a new combat should be made, or if these
        ' units should be added to an existing combat.
        ' the unit being bumped into is considered the 'defender'. Additional units are marked as defendingsupport or attackingsupport
        ' marks the battle as active in a particular phase

        ' 1 check to see if target unit is already engaged, if so, add 'unit' to the battle targetunit is involved in.
        ' 2 check to see if this combat would be within 'joinCombatRange', from EITHER units' point of view, if so, add them both.
        ' 3 if either '1' or '2' do not apply, create a new combat.
        Dim batt As cmplib01.Battle_2

        ' if there are no battles currently in the list, we don't need any checks we just create a new battle and exit
        If ptrGameData.Battles_g.HT.Count = 0 Then
            AddNewbattle(unit, target, inPhase)
            Exit Sub
        End If

        If target.Status = cmplib01.GroundUnitStatus_cgd.Engaged Then
            Try
                batt = target.battleInvolvedIn
                ' add the new contact to this combat.
                batt.InvolvedChits.add(unit)
                unit.Status = cmplib01.GroundUnitStatus_cgd.Engaged
                ' also set this unit to supporting attack or defense, depending on ORIGINAL units.
                SetUnitbattlePosture(unit, batt)
                ' and now, get the hell out!
                Exit Sub
            Catch argEx As ArgumentException
                Exit Sub
            Catch ex As Exception
                HandleException(c_Module, ex)
                Exit Sub
            End Try
        End If
        ' target is NOT already engaged in combat, check range to existing combats (if we are down here,
        ' we already know there are other combats occuring), if within range, add both units to that combat.
        ' both of these units are considered supporting their faction, whether its attacking or defending (check the units involved 
        ' list to make sure the correct battleposture is set.
        Dim key As String
        Dim distOne As Int16
        Dim distTwo As Int16
        Dim closeDist As Int16
        Dim closestDist As Int16 = 30000
        Dim closestbattleKey As String

        For Each key In ptrGameData.Battles_g.HT.Keys
            batt = ptrGameData.Battles_g.Item(key)
            distOne = XYDistance(unit.Location.X, batt.BattleLocation.X, unit.Location.Y, batt.BattleLocation.Y)
            distTwo = XYDistance(target.Location.X, batt.BattleLocation.X, target.Location.Y, batt.BattleLocation.Y)
            If distOne < distTwo Then
                closeDist = distOne
            Else
                closeDist = distTwo
            End If
            ' we are trying to determine which battle is the closest
            If closeDist < closestDist Then
                closestbattleKey = batt.Key
                closestDist = closeDist
            End If
        Next
        ' determine the distance from the closest unit (to the closest battle)
        If closestDist <= joinCombatDistance Then
            ' add both units to the closest battle, and then set their battle posture
            Try
                batt = ptrGameData.Battles_g.Item(closestbattleKey)
                batt.InvolvedChits.add(unit)
                batt.InvolvedChits.add(unit)
                target.Status = cmplib01.GroundUnitStatus_cgd.Engaged
                unit.Status = cmplib01.GroundUnitStatus_cgd.Engaged
                ' set the units battle postures accordingly
                SetUnitbattlePosture(unit, batt)
                SetUnitbattlePosture(target, batt)
            Catch ex As Exception
                HandleException(c_Module, ex)
            End Try
        Else
            AddNewbattle(unit, target, inPhase)
        End If

    End Sub

    Private Sub SetCombatFlag(ByRef ptrUnit As ChitMember, ByRef ptrTarget As ChitMember)
        ' finds the owning player and sets his IsInCombat flag.
        Dim playKey As String
        Dim play As cmplib01.Player

        For Each playKey In ptrGameData.Players.Keys
            play = ptrGameData.Players.Item(playKey)
            If play.PlayerID = ptrUnit.OwningPlayer.PlayerID Then
                play.IsInCombat = True
            End If
            If play.PlayerID = ptrTarget.OwningPlayer.PlayerID Then
                play.IsInCombat = True
            End If
        Next

    End Sub

    Private Sub SetCombatFlag(ByRef ptrUnit As ChitMember, ByRef ptrTarget As InstallationChit)
        Dim factID As Integer = ptrTarget.OwningFaction.FactionID
        Dim factKey As String = "FACT" & factID
        Dim playKey As String
        Dim play As cmplib01.Player

        For Each playKey In ptrGameData.Players.Keys
            play = ptrGameData.Players.Item(playKey)
            If play.PlayerID = ptrUnit.OwningPlayer.PlayerID Then
                play.IsInCombat = True
            End If
            If play.FactionKey = factKey Then
                play.IsInCombat = True
            End If
        Next

    End Sub

    Private Sub SetUnitbattlePosture(ByRef unit As ChitMember, ByRef batt As cmplib01.Battle)
        Dim testUnit As ChitMember
        'Dim key As String

        ' TODO: This handles only TWO factions involved.
        For Each testUnit In batt.InvolvedChits

            If testUnit.OwningFaction.Equals(unit.OwningFaction) Then
                If testUnit.battleInvolvedIn.Equals(unit.battleInvolvedIn) Then
                    unit.currentBattlePosture = testUnit.currentBattlePosture
                    Exit For
                End If
            End If
        Next

    End Sub

    Private Sub ResetStatus()
        ' resets things like detectedthisturn and such
        'Dim key As String
        'Dim gc As cmplib01.GroundChitType
        'Dim unit As cmplib01.UnitType
        Dim pixelsPerOneMile As Single = ptrFMPData.MapScale.PixelCount / ptrFMPData.MapScale.MilesPerPixelCount
        Dim turnMultiplier As Single  ' used to get the correct speed of a unit

        Try
            For Each mem As ChitMember In ptrGameData.Chits

                If mem.UnitType = GroundChitClass_cgd.Battlegroup Then
                    Dim batt As BattlegroupChit = mem

                    '// here we set up the movement value for it if its a battlegroup (transport, etc)
                    batt.calculateProperties()


                    ' apply the GroundUnitStatus rules
                    ResetGroundUnitStatus(batt)
                    '// other properties
                    batt.detectedThisTurn = False
                    batt.currentBattlePosture = cmplib01.BattlePosture_cgd.NoBattle
                    'batt.TotalDistanceMovedThisTurn = 0
                    batt.invalidWaypoint = False
                    batt.distanceTravelled = 0

                    If batt.historicalPosition Is Nothing Then batt.historicalPosition = New ArrayList
                    batt.historicalPosition.Clear()

                    ' reset maximum movement
                    ' determine how many pixels a unit can move per game turn.
                    Select Case ptrGameData.TurnLength
                        Case cmplib01.TurnLength_cgd.Hour : turnMultiplier = 1
                        Case cmplib01.TurnLength_cgd.HalfDay : turnMultiplier = 5 ' we move up to 10 hours per day
                        Case cmplib01.TurnLength_cgd.FullDay : turnMultiplier = 10
                        Case cmplib01.TurnLength_cgd.Week : turnMultiplier = 70
                        Case cmplib01.TurnLength_cgd.Month : turnMultiplier = 300
                        Case cmplib01.TurnLength_cgd.HalfHour : turnMultiplier = 0.5
                        Case cmplib01.TurnLength_cgd.FifteenMinute : turnMultiplier = 0.25
                        Case cmplib01.TurnLength_cgd.FiveMinute : turnMultiplier = 0.08
                    End Select

                    batt.effectiveSpeed = batt.movementSpeed * pixelsPerOneMile * turnMultiplier
                    batt.moveRemaining = batt.movementSpeed * pixelsPerOneMile * turnMultiplier

                ElseIf mem.UnitType = GroundChitClass_cgd.Objective Then
                    mem.detectedThisTurn = False
                    mem.currentBattlePosture = cmplib01.BattlePosture_cgd.NoBattle
                End If
            Next

        Catch ex As Exception
            HandleException("CampaignerCombatEngineB.ResetStatus", ex)
        End Try

        ' until we actually handle combat, we'll remove all of the battles
        ptrGameData.Battles_g.HT.Clear()

    End Sub

    Private Sub ResetGroundUnitStatus(ByRef mem As ChitMember)
        Select Case mem.Status
            Case GroundUnitStatus_cgd.Regrouping
                mem.Status = GroundUnitStatus_cgd.Regrouped
            Case GroundUnitStatus_cgd.Dead, GroundUnitStatus_cgd.NotDeployed
                '// keeps the same status

            Case Else
                mem.Status = GroundUnitStatus_cgd.OK

        End Select
        'Select Case GC.Status
        '    Case cmplib01.GroundUnitStatus_cgd.Regrouping
        '        ' after losing a battle, the chit must regroup. It can't move until after it is "Regrouped"
        '        GC.Status = cmplib01.GroundUnitStatus_cgd.Regrouped
        '    Case GroundUnitStatus_cgd.InTransport, GroundUnitStatus_cgd.LoadingTransport
        '        GC.Status = GroundUnitStatus_cgd.InTransport
        '    Case GroundUnitStatus_cgd.UnloadingFromTransport
        '        GC.Status = GroundUnitStatus_cgd.OK
        '    Case Else
        '        GC.Status = cmplib01.GroundUnitStatus_cgd.OK
        'End Select
    End Sub

    Private Sub AddNewbattle(ByRef unit As ChitMember, ByRef targetUnit As ChitMember, ByVal inPhase As Integer)
        ' if both units are moving, the battle is located between them, if one is not moving, the battle is located at HIS coords
        ' TODO: make the battle at the correct location depending on who is moving, plus other rules that will most likely become
        ' apparent after a beta game is running.
        Dim batt As New cmplib01.Battle_2

        Try
            batt.BattleLocation = LocateNewbattle(unit.Location, targetUnit.Location)
            batt.InvolvedChits.add(unit)
            batt.InvolvedChits.add(targetUnit)

            'If TypeOf targetUnit Is ObjectiveType Then
            '    Dim obj As ObjectiveType = targetUnit
            '    batt.InvolvedChits.add(obj.Key, targetUnit)
            'Else
            '    batt.InvolvedChits.add(targetUnit.Key, targetUnit)
            'End If

            batt.PhaseActive = inPhase

            batt.BattleName = unit.Name & " vs " & targetUnit.Name
            targetUnit.Status = cmplib01.GroundUnitStatus_cgd.Engaged
            targetUnit.battleInvolvedIn = batt
            unit.Status = cmplib01.GroundUnitStatus_cgd.Engaged
            unit.battleInvolvedIn = batt

            ' the unit being bumped into is considered  'defending', the other is 'attacking'
            unit.CurrentBattlePosture = cmplib01.BattlePosture_cgd.Attacking
            targetUnit.CurrentBattlePosture = cmplib01.BattlePosture_cgd.Defending

            ' apply the correct faction ids to attacking and defending in the battle for future reference.
            batt.AttackingFactionID = unit.OwningFaction.FactionID
            batt.DefendingFactionID = targetUnit.OwningFaction.FactionID

            ptrGameData.Battles_g.Add(batt, batt.Key)

        Catch ex As Exception
            HandleException(c_Module, ex)
        End Try

    End Sub

    Private Function LocateNewbattle(ByVal pntone As Point, ByVal pnttwo As Point) As Point
        ' new battles are located between the two units (points provided)
        Dim distance As Int32 = (XYDistance(pntone.X, pnttwo.X, pntone.Y, pnttwo.Y) / 2)
        Dim xStr As Single = GetXorYStrength(cmXorY.cmX, pntone.X, pnttwo.X, pntone.Y, pnttwo.Y)
        Dim yStr As Single = GetXorYStrength(cmXorY.cmY, pntone.X, pnttwo.X, pntone.Y, pnttwo.Y)
        Dim location As New Point

        location.X = pntone.X + (distance * xStr)
        location.Y = pntone.Y + (distance * yStr)

        Return location
    End Function

    Private Sub IncreaseDetectionOnTarget(ByRef fact As cmplib01.Faction, ByRef target As ChitMember, Optional ByVal ToKnown As Boolean = True)
        Try
            If Not ToKnown Then
                ' if it is toknown, then we don't care if its been detected or not. It becomes KNOWN!
                If target.detectedThisTurn = True Then Exit Sub
            End If

            ' see if this unit already exists in the faction's contact list, if it does increase the detection level, if not, add one.
            If fact.HTChitDetection.ContainsKey(target.Name) Then
                Dim det As cmplib01.ChitDetection = fact.HTChitDetection.Item(target.Name)
                If ToKnown = True Then
                    det.DetectionLevel = c_MaxChitDetectionLevel
                Else

#If MIXEDMODE = 1 Then
                    If det.ChitDetectedThisTurn = False Then
                        '// if we were already detected, we don't need to do anything, so huzzah.
                        det.DetectionLevel = 2
                    End If
#Else
                '// increase detection by one
                det.DetectionLevel += 1
#End If

                    If det.DetectionLevel > c_MaxChitDetectionLevel Then det.DetectionLevel = c_MaxChitDetectionLevel
                End If

                target.detectedThisTurn = True
                det.ChitDetectedThisTurn = True
            Else
                '// nothing special needs to be done if it isn't already in the list. :D
                Dim det As New cmplib01.ChitDetection

                det.ChitDetectedThisTurn = True

                If ToKnown = True Then
                    det.DetectionLevel = c_MaxChitDetectionLevel
                Else
                    det.DetectionLevel = 2
                End If

                det.Chit = target
                fact.HTChitDetection.Add(target.Name, det)
                target.detectedThisTurn = True

            End If
        Catch ex As Exception
            HandleException(c_Module, ex)
        End Try

    End Sub

    Private Sub HandleDetection(ByRef fact As cmplib01.Faction, ByRef target As ChitMember, Optional ByVal toKnown As Boolean = True)
        Try
            Dim key As String = target.Name

            Const c_DETLEVEL As Integer = 2

            '// we don't have to do anything else if this guy was detected already, and its not a 'toknown'.
            If toKnown = False And target.DetectedThisTurn = True Then Exit Sub

            '// see if there is an entry for this sukka
            If fact.HTChitDetection.ContainsKey(key) Then
                Dim det As ChitDetection = fact.HTChitDetection.Item(key)

                '//////////////////////NEW//////////////////////
                '// if he already has an entry, and is equal or higher than our base detection level, we don't stop.
                'If det.DetectionLevel < c_DETLEVEL Then
                '    '// this guy had left detection and now is back. This is a detection halt
                '    detectionHalt = True
                'End If
                '//////////////////////NEW//////////////////////

                If toKnown Then
                    det.DetectionLevel = c_MaxChitDetectionLevel
                Else
                    det.DetectionLevel = c_DETLEVEL
                End If
                det.ChitDetectedThisTurn = True
                target.DetectedThisTurn = True
                det.PhaseDetected = _currentPhase
            Else
                '// does not exist.
                Dim det As New ChitDetection
                det.ChitDetectedThisTurn = True

                '//////////////////////NEW//////////////////////
                detectionHalt = True    '// this is definately a detection halt.
                '//////////////////////NEW//////////////////////

                If toKnown Then
                    det.DetectionLevel = c_MaxChitDetectionLevel
                Else
                    det.DetectionLevel = c_DETLEVEL
                End If

                det.Chit = target
                target.DetectedThisTurn = True
                det.PhaseDetected = _currentPhase
                fact.HTChitDetection.Add(key, det)
            End If


        Catch ex As Exception
            HandleException(c_Module, ex)
        End Try

    End Sub

    Private Sub DecreaseDetectionForUnspotted()
        ' reduces the detection level on each unit that was no longer spotted this turn
        Dim factKey As String
        Dim fact As cmplib01.Faction

        '        For Each mem As ChitMember In ptrGameData.Chits
        '#If DEBUG Then
        '            Debug.WriteLine(mem.Name)
        '#End If
        '            If mem.detectedThisTurn = False Then

        '                For Each factKey In ptrGameData.Faction_g.HT.Keys
        '                    fact = ptrGameData.Faction_g.Item(factKey)
        '                    If Not mem.OwningFaction.Equals(fact) Then
        '                        Dim det As ChitDetection = fact.HTChitDetection.Item(mem.Name)
        '                        If Not det Is Nothing Then
        '                            If det.DetectionLevel > 2 Then
        '                                det.DetectionLevel = 1
        '                                Exit For
        '                            Else
        '                                det.DetectionLevel = 0
        '                                Exit For
        '                            End If
        '                        End If
        '                    End If
        '                Next

        '            End If
        '        Next

        Dim detKey As String
        For Each factKey In ptrGameData.Faction_g.HT.Keys
            fact = ptrGameData.Faction_g.Item(factKey)
            For Each detKey In fact.HTChitDetection.Keys
                Dim det As ChitDetection = fact.HTChitDetection.Item(detKey)
                If det.Chit.detectedThisTurn = False Then
                    '// reduce the level by one
                    det.DetectionLevel -= 1
                    If det.DetectionLevel < 0 Then det.DetectionLevel = 0
                End If
            Next
        Next


        'For Each gcKey In ptrGameData.AllChits.Keys
        '    gc = ptrGameData.AllChits.Item(gcKey)
        '    If gc.DetectedThisTurn = False Then
        '        ' see if this unit exists in enemy detectionlist


        '        For Each factKey In ptrGameData.Faction_g.HT.Keys
        '            fact = ptrGameData.Faction_g.Item(factKey)
        '            If gc.OwningFaction <> fact.FactionID Then
        '                ' see if this ground chit is in this faction's list

        '                If fact.HTChitDetection.ContainsKey(gcKey) Then
        '                    Dim det As cmplib01.ChitDetection = fact.HTChitDetection.Item(gcKey)
        '                    If det.DetectionLevel > 2 Then
        '                        det.DetectionLevel = 1
        '                        Exit For
        '                    Else
        '                        det.DetectionLevel = 0
        '                        Exit For
        '                    End If
        '                End If
        '            End If
        '        Next
        '    End If
        'Next

    End Sub

    Private Sub ResetDeploymentValues()
        ' resets the deploymentzone amount available in this turn.
        Dim dep As cmplib01.DeploymentZone
        Dim depKey As String

        For Each depKey In ptrGameData.DeploymentZones_g.HT.Keys
            dep = ptrGameData.DeploymentZones_g.HT.Item(depKey)
            dep.PointsDeployedThisTurn = 0
        Next
    End Sub



#Region "Implemented Methods"
    Public Sub OpenCombatEngine(ByVal filePath As String) Implements ICombatEngine.ICombatEngine.OpenCombatEngine

    End Sub

    Public Sub SaveCombatEngine(ByVal filePath As String) Implements ICombatEngine.ICombatEngine.SaveCombatEngine

    End Sub

    Public Sub ShowPostCombatWindow() Implements ICombatEngine.ICombatEngine.ShowPostCombatWindow

    End Sub

    Public Sub ShowPreCombatWindow() Implements ICombatEngine.ICombatEngine.ShowPreCombatWindow

    End Sub
#End Region

#Region "After Combat"

    Public Sub ApplyCombatResults(ByRef GameData As cmplib01.CampaignerGameData)
        ' checks each battle and moves any units that need to be moved and reassigns objectives to victorous units.
        Dim key As String
        Dim batt As cmplib01.Battle
        'Dim gc As cmplib01.GroundChitType
        'Dim unit As cmplib01.UnitType
        'Dim obj As cmplib01.ObjectiveType
        'Dim gcKey As String




        If GameData.Battles_g.HT.Count > 0 Then
            ' step through each battle
            For Each key In GameData.Battles_g.HT.Keys
                batt = GameData.Battles_g.Item(key)

                For Each mem As ChitMember In batt.InvolvedChits
                    If mem.Status = GroundUnitStatus_cgd.Dead Then
                        '// doin' nuthin'
                    Else
                        Select Case mem.UnitType
                            Case GroundChitClass_cgd.Battlegroup
                                UnitbattleResult(mem, batt)
                            Case GroundChitClass_cgd.Objective
                                ObjectivebattleResult(mem, batt, GameData)
                        End Select
                    End If
                Next

                'For Each gcKey In batt.InvolvedChits.Keys
                '    gc = batt.InvolvedChits.Item(gcKey)

                '    '// if the chit is dead, we don't have to change anything
                '    If gc.Status = GroundUnitStatus_cgd.Dead Then
                '        MessageBox.Show(gc.Name & " is dead, dead, dead.")
                '    Else
                '        If gc.GroundChitClass = cmplib01.GroundChitClass_cgd.Unit Then
                '            ' determine the result 
                '            unit = CType(gc, cmplib01.UnitType)
                '            UnitbattleResult(unit, batt)
                '        ElseIf gc.GroundChitClass = cmplib01.GroundChitClass_cgd.Objective Then
                '            ' determine the result
                '            obj = CType(gc, cmplib01.ObjectiveType)
                '            ObjectivebattleResult(obj, batt, GameData)
                '        End If
                '    End If
                'Next gcKey

            Next key
        Else
            Exit Sub
        End If

    End Sub

    Private Sub UnitbattleResult(ByRef unit As BattlegroupChit, ByVal batt As cmplib01.Battle)
        ' used to apply the correct result to a unit
        Dim battlelocation As Point = batt.BattleLocation

        ' apply the battleresult to this unit, this sets the correct battle result
        AssignbattleResultToGroundChit(unit, batt)

        Select Case unit.BattleResult
            Case cmplib01.UnitBattleResult_cgd.Defeat
                KnockUnitBack(unit, 20, battlelocation)
                unit.Status = cmplib01.GroundUnitStatus_cgd.Regrouping
            Case cmplib01.UnitBattleResult_cgd.Draw
                unit.Status = cmplib01.GroundUnitStatus_cgd.OK
            Case cmplib01.UnitBattleResult_cgd.MarginalDefeat
                KnockUnitBack(unit, 10, battlelocation)
                unit.Status = cmplib01.GroundUnitStatus_cgd.OK
            Case cmplib01.UnitBattleResult_cgd.MarginalVictory
                unit.Status = cmplib01.GroundUnitStatus_cgd.OK
            Case cmplib01.UnitBattleResult_cgd.Victory
                unit.Status = cmplib01.GroundUnitStatus_cgd.OK
        End Select
    End Sub

    Private Sub ObjectivebattleResult(ByRef obj As InstallationChit, ByVal batt As cmplib01.Battle, ByRef gameData As CampaignerGameData)
        ' used to apply the correct result to an objective and change ownership

        AssignbattleResultToGroundChit(obj, batt)

        ' apply the battleresult to this objective, which sets the correct battle result.
        ' any victory for the attacker will take ownership of the objective
        Select Case obj.BattleResult
            Case cmplib01.UnitBattleResult_cgd.Defeat
                ' give the objective to the attacker
                obj.OwningFaction = gameData.Faction_g.Item(CampaignerGameData.CDGKEY_FACTION & batt.AttackingFactionID)
                '// remove the installation from the attacking factions detection
                '// and add it to the defending faction's detection!
                Dim deffact As Faction = gameData.Faction_g.Item(CampaignerGameData.CDGKEY_FACTION & batt.DefendingFactionID)
                Dim attfact As Faction = gameData.Faction_g.Item(CampaignerGameData.CDGKEY_FACTION & batt.AttackingFactionID)
                Dim detKey As String
                For Each detKey In attfact.HTChitDetection.Keys
                    Debug.WriteLine(detKey)
                Next

            Case cmplib01.UnitBattleResult_cgd.MarginalDefeat
                obj.OwningFaction = gameData.Faction_g.Item(CampaignerGameData.CDGKEY_FACTION & batt.AttackingFactionID)
                Dim deffact As Faction = gameData.Faction_g.Item(CampaignerGameData.CDGKEY_FACTION & batt.DefendingFactionID)
                Dim attfact As Faction = gameData.Faction_g.Item(CampaignerGameData.CDGKEY_FACTION & batt.AttackingFactionID)
                Dim detKey As String
                For Each detKey In attfact.HTChitDetection.Keys
                    Debug.WriteLine(detKey)
                Next

        End Select

    End Sub

    Private Sub KnockUnitBack(ByRef unit As BattlegroupChit, ByVal distance As Int16, ByVal fromLocation As Point)
        ' if a unit is knocked back into a terrain it can't move into, it should be DESTROYED!!! See CampaignerCombat.txt
        Dim xStr As Single = GetXorYStrength(cmXorY.cmX, unit.Location.X, fromLocation.X, unit.Location.Y, fromLocation.Y)
        Dim yStr As Single = GetXorYStrength(cmXorY.cmY, unit.Location.X, fromLocation.X, unit.Location.Y, fromLocation.Y)
        Dim newLocation As New Point(unit.Location.X, unit.Location.Y)

        'reverse the values so they move in the correct direction
        xStr = xStr * -1
        yStr = yStr * -1

        newLocation.X = unit.Location.X + (distance * xStr)
        newLocation.Y = unit.Location.Y + (distance * yStr)
        unit.Location = newLocation

    End Sub

    Private Sub AssignbattleResultToGroundChit(ByRef gChit As ChitMember, ByRef batt As cmplib01.Battle)
        ' HACK: There is a better way to do this than brute force... figure it out.
        Select Case gChit.CurrentBattlePosture
            Case cmplib01.BattlePosture_cgd.Attacking
                Select Case batt.BattleResult
                    Case cmplib01.BattleResult_cgd.AttackerVictory : gChit.BattleResult = cmplib01.UnitBattleResult_cgd.Victory
                    Case cmplib01.BattleResult_cgd.AttackerMarginalVictory : gChit.BattleResult = cmplib01.UnitBattleResult_cgd.MarginalVictory
                    Case cmplib01.BattleResult_cgd.DefenderMarginalVictory : gChit.BattleResult = cmplib01.UnitBattleResult_cgd.MarginalDefeat
                    Case cmplib01.BattleResult_cgd.DefenderVictory : gChit.BattleResult = cmplib01.UnitBattleResult_cgd.Defeat
                    Case cmplib01.BattleResult_cgd.Draw : gChit.BattleResult = cmplib01.UnitBattleResult_cgd.Draw
                End Select
            Case cmplib01.BattlePosture_cgd.AttackingIndirectSupport
                Select Case batt.BattleResult
                    Case cmplib01.BattleResult_cgd.AttackerVictory : gChit.BattleResult = cmplib01.UnitBattleResult_cgd.MarginalVictory
                    Case cmplib01.BattleResult_cgd.AttackerMarginalVictory : gChit.BattleResult = cmplib01.UnitBattleResult_cgd.MarginalVictory
                    Case cmplib01.BattleResult_cgd.DefenderMarginalVictory : gChit.BattleResult = cmplib01.UnitBattleResult_cgd.Draw
                    Case cmplib01.BattleResult_cgd.DefenderVictory : gChit.BattleResult = cmplib01.UnitBattleResult_cgd.Defeat
                    Case cmplib01.BattleResult_cgd.Draw : gChit.BattleResult = cmplib01.UnitBattleResult_cgd.Draw
                End Select
            Case cmplib01.BattlePosture_cgd.AttackingReserve
                Select Case batt.BattleResult
                    Case cmplib01.BattleResult_cgd.AttackerVictory : gChit.BattleResult = cmplib01.UnitBattleResult_cgd.MarginalVictory
                    Case cmplib01.BattleResult_cgd.AttackerMarginalVictory : gChit.BattleResult = cmplib01.UnitBattleResult_cgd.Draw
                    Case cmplib01.BattleResult_cgd.DefenderMarginalVictory : gChit.BattleResult = cmplib01.UnitBattleResult_cgd.Draw
                    Case cmplib01.BattleResult_cgd.DefenderVictory : gChit.BattleResult = cmplib01.UnitBattleResult_cgd.MarginalDefeat
                    Case cmplib01.BattleResult_cgd.Draw : gChit.BattleResult = cmplib01.UnitBattleResult_cgd.Draw
                End Select
            Case cmplib01.BattlePosture_cgd.AttackingSupport ' same as indirect support
                Select Case batt.BattleResult
                    Case cmplib01.BattleResult_cgd.AttackerVictory : gChit.BattleResult = cmplib01.UnitBattleResult_cgd.MarginalVictory
                    Case cmplib01.BattleResult_cgd.AttackerMarginalVictory : gChit.BattleResult = cmplib01.UnitBattleResult_cgd.MarginalVictory
                    Case cmplib01.BattleResult_cgd.DefenderMarginalVictory : gChit.BattleResult = cmplib01.UnitBattleResult_cgd.Draw
                    Case cmplib01.BattleResult_cgd.DefenderVictory : gChit.BattleResult = cmplib01.UnitBattleResult_cgd.Defeat
                    Case cmplib01.BattleResult_cgd.Draw : gChit.BattleResult = cmplib01.UnitBattleResult_cgd.Draw
                End Select
            Case cmplib01.BattlePosture_cgd.Defending
                Select Case batt.BattleResult
                    Case cmplib01.BattleResult_cgd.AttackerVictory : gChit.BattleResult = cmplib01.UnitBattleResult_cgd.Defeat
                    Case cmplib01.BattleResult_cgd.AttackerMarginalVictory : gChit.BattleResult = cmplib01.UnitBattleResult_cgd.MarginalDefeat
                    Case cmplib01.BattleResult_cgd.DefenderMarginalVictory : gChit.BattleResult = cmplib01.UnitBattleResult_cgd.MarginalVictory
                    Case cmplib01.BattleResult_cgd.DefenderVictory : gChit.BattleResult = cmplib01.UnitBattleResult_cgd.Victory
                    Case cmplib01.BattleResult_cgd.Draw : gChit.BattleResult = cmplib01.UnitBattleResult_cgd.Draw
                End Select
            Case cmplib01.BattlePosture_cgd.DefendingIndirectSupport
                Select Case batt.BattleResult
                    Case cmplib01.BattleResult_cgd.AttackerVictory : gChit.BattleResult = cmplib01.UnitBattleResult_cgd.MarginalDefeat
                    Case cmplib01.BattleResult_cgd.AttackerMarginalVictory : gChit.BattleResult = cmplib01.UnitBattleResult_cgd.Draw
                    Case cmplib01.BattleResult_cgd.DefenderMarginalVictory : gChit.BattleResult = cmplib01.UnitBattleResult_cgd.MarginalVictory
                    Case cmplib01.BattleResult_cgd.DefenderVictory : gChit.BattleResult = cmplib01.UnitBattleResult_cgd.MarginalVictory
                    Case cmplib01.BattleResult_cgd.Draw : gChit.BattleResult = cmplib01.UnitBattleResult_cgd.Draw
                End Select
            Case cmplib01.BattlePosture_cgd.DefendingReserve
                Select Case batt.BattleResult
                    Case cmplib01.BattleResult_cgd.AttackerVictory : gChit.BattleResult = cmplib01.UnitBattleResult_cgd.MarginalDefeat
                    Case cmplib01.BattleResult_cgd.AttackerMarginalVictory : gChit.BattleResult = cmplib01.UnitBattleResult_cgd.Draw
                    Case cmplib01.BattleResult_cgd.DefenderMarginalVictory : gChit.BattleResult = cmplib01.UnitBattleResult_cgd.Draw
                    Case cmplib01.BattleResult_cgd.DefenderVictory : gChit.BattleResult = cmplib01.UnitBattleResult_cgd.MarginalVictory
                    Case cmplib01.BattleResult_cgd.Draw : gChit.BattleResult = cmplib01.UnitBattleResult_cgd.Draw
                End Select
            Case cmplib01.BattlePosture_cgd.DefendingSupport ' same as indirect support
                Select Case batt.BattleResult
                    Case cmplib01.BattleResult_cgd.AttackerVictory : gChit.BattleResult = cmplib01.UnitBattleResult_cgd.MarginalDefeat
                    Case cmplib01.BattleResult_cgd.AttackerMarginalVictory : gChit.BattleResult = cmplib01.UnitBattleResult_cgd.Draw
                    Case cmplib01.BattleResult_cgd.DefenderMarginalVictory : gChit.BattleResult = cmplib01.UnitBattleResult_cgd.MarginalVictory
                    Case cmplib01.BattleResult_cgd.DefenderVictory : gChit.BattleResult = cmplib01.UnitBattleResult_cgd.MarginalVictory
                    Case cmplib01.BattleResult_cgd.Draw : gChit.BattleResult = cmplib01.UnitBattleResult_cgd.Draw
                End Select
            Case cmplib01.BattlePosture_cgd.NoBattle
                gChit.BattleResult = cmplib01.UnitBattleResult_cgd.NoBattle
        End Select
    End Sub

#End Region

#Region "Properties"
    Public Property UsesContactCombat() As Boolean Implements ICombatEngine.ICombatEngine.UsesContactCombat
        Get
            Return True
        End Get
        Set(ByVal Value As Boolean)

        End Set
    End Property

    Public Property UsesPrecombatWindow() As Boolean Implements ICombatEngine.ICombatEngine.UsesPrecombatWindow
        Get
            Return True
        End Get
        Set(ByVal Value As Boolean)

        End Set
    End Property

    Public Property UsesRangedCombat() As Boolean Implements ICombatEngine.ICombatEngine.UsesRangedCombat
        Get
            Return False
        End Get
        Set(ByVal Value As Boolean)

        End Set
    End Property

#End Region

End Class
